package cn.dansj.plugin;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import java.util.*;
import java.util.stream.Collectors;

public class ConditionalOnClassAnnotationVisitor extends ClassVisitor {
    private boolean transformed = false;
    private static final List<String> conditionalOnClassAnnotations = new ArrayList<String>() {{
        add("cn.dansj.common.utils.spring.context.condition.ConditionalOnClass");
        add("org.springframework.boot.autoconfigure.condition.ConditionalOnClass");
    }}.stream().map(e -> "L" + e.replace('.', '/') + ";").collect(Collectors.toList());

    public ConditionalOnClassAnnotationVisitor(ClassVisitor cv) {
        super(Opcodes.ASM9, cv);
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces);
    }

    @Override
    public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
        AnnotationVisitor av = super.visitAnnotation(descriptor, visible);
        if (conditionalOnClassAnnotations.contains(descriptor)) {
            return new ConditionalOnClassAnnotationTransformer(av, this);
        }
        return av;
    }

    @Override
    public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
        FieldVisitor fv = super.visitField(access, name, descriptor, signature, value);
        return new FieldVisitor(Opcodes.ASM9, fv) {
            @Override
            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
                AnnotationVisitor av = super.visitAnnotation(desc, visible);
                if (conditionalOnClassAnnotations.contains(desc)) {
                    return new ConditionalOnClassAnnotationTransformer(av, ConditionalOnClassAnnotationVisitor.this);
                }
                return av;
            }
        };
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
        return new MethodVisitor(Opcodes.ASM9, mv) {
            @Override
            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
                AnnotationVisitor av = super.visitAnnotation(desc, visible);
                if (conditionalOnClassAnnotations.contains(desc)) {
                    return new ConditionalOnClassAnnotationTransformer(av, ConditionalOnClassAnnotationVisitor.this);
                }
                return av;
            }
        };
    }

    public void markTransformed() {
        this.transformed = true;
    }

    public boolean wasTransformed() {
        return transformed;
    }

    private static class ConditionalOnClassAnnotationTransformer extends AnnotationVisitor {
        private final ConditionalOnClassAnnotationVisitor parent;
        private final Set<String> mergedNames = new LinkedHashSet<>();

        public ConditionalOnClassAnnotationTransformer(AnnotationVisitor av, ConditionalOnClassAnnotationVisitor parent) {
            super(Opcodes.ASM9, av);
            this.parent = parent;
        }

        @Override
        public AnnotationVisitor visitArray(String name) {
            if ("value".equals(name)) {
                return new ValueArrayVisitor(this);
            } else if ("name".equals(name)) {
                return new NameArrayVisitor(this);
            }
            return super.visitArray(name);
        }

        @Override
        public void visitEnd() {
            // Only transform if we found value or name attributes
            if (!mergedNames.isEmpty()) {
                parent.markTransformed();
                // Create new name array with merged values
                AnnotationVisitor nameArray = super.visitArray("name");
                if (nameArray != null) {
                    for (String nameValue : mergedNames) {
                        nameArray.visit(null, nameValue);
                    }
                    nameArray.visitEnd();
                }

                // Create empty value array
                AnnotationVisitor valueArray = super.visitArray("value");
                if (valueArray != null) valueArray.visitEnd();
            }

            super.visitEnd();
        }
    }

    // 处理value数组的访问器
    private static class ValueArrayVisitor extends AnnotationVisitor {
        private final ConditionalOnClassAnnotationTransformer parentTransformer;

        public ValueArrayVisitor(ConditionalOnClassAnnotationTransformer parent) {
            super(Opcodes.ASM9, null); // 不传递给父类
            this.parentTransformer = parent;
        }

        @Override
        public void visit(String name, Object value) {
            if (value instanceof Type) {
                String className = ((Type) value).getClassName();
                parentTransformer.mergedNames.add(className);
            }
        }

        @Override
        public void visitEnd() {
        }
    }

    // 处理name数组的访问器
    private static class NameArrayVisitor extends AnnotationVisitor {
        private final ConditionalOnClassAnnotationTransformer parentTransformer;

        public NameArrayVisitor(ConditionalOnClassAnnotationTransformer parent) {
            super(Opcodes.ASM9, null); // 不传递给父类
            this.parentTransformer = parent;
        }

        @Override
        public void visit(String name, Object value) {
            if (value instanceof String) {
                String strValue = (String) value;
                parentTransformer.mergedNames.add(strValue);
            }
        }

        @Override
        public void visitEnd() {
        }
    }
}